import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
import { Vector3, VSMShadowMap, TextureLoader, Group, Clock, ShaderMaterial, Mesh, RepeatWrapping, DoubleSide, AdditiveBlending, CylinderGeometry, Matrix4, MultiplyBlending, Vector2, PerspectiveCamera, WebGLRenderer, Scene, MeshStandardMaterial, BoxGeometry, DirectionalLight } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import GUI from "three/examples/jsm/libs/lil-gui.module.min.js";
import { getAshesMat, getFireMat } from "./materials";
import { canvasToImage } from "../utils/image";
// import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
const gltfLoader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco/");
gltfLoader.setDRACOLoader(dracoLoader);
export function initFire(camera:PerspectiveCamera, renderer:WebGLRenderer, scene:Scene,controls:OrbitControls) {
// 这个着色器，就是把原本的纹理，转换成灰度图，估计是为了提高明度的精度，这样明暗变化会丝滑一些
/**
 * 目前来说壁炉的整体明度系数高，但是地面的贴图本身比较暗
 */
  const rgbLightmapFrag = /*glsl */`
  uniform sampler2D map;
  uniform vec3 ratio;
  uniform float gamma;
  varying vec2 vUv;
  void main(void) {
    vec4 tex = texture2D(map, vUv);
    // using RGB channels of the texture de vary the lighting
    tex.rgb *= ratio;
    float col = tex.r+ tex.g + tex.b;
    // adjust contrast 调节对比度
    col = pow(col, gamma);
    gl_FragColor = linearToOutputTexel(vec4(col, col, col, 1.));
  }`;

  const basicVert = /*glsl */`
  precision highp float;
  varying vec2 vUv;
  void main() {
    vUv = uv;
    vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
    gl_Position = projectionMatrix * modelViewPosition; 
  }`;


  const gltfFile = "/fireplace.glb";
  const noiseFile = "/noise_1.jpg";
  controls.target = new Vector3(0, 0, 0);
  camera.position.set(0, 0.5, 1.5);
  controls.update()
  const imageLoader = new TextureLoader();
  let model: Group;




  let clock = new Clock();
  let time = 0;
  let deltaTime = 0;
  const fireConfig = {
    fireSpeed :1,
    bloom:true,
    brightness:1,
    needShot:false,
    shot(){
      fireConfig.needShot = true;
    }

  }
  let fireMat: ShaderMaterial,bloomPass: UnrealBloomPass,ashesMat: ShaderMaterial;
//   @ts-ignore
  let fireplace: Mesh = new Group(), fire: Mesh, ashes: Mesh, composer: EffectComposer;
  let fireplaceMat: ShaderMaterial, floorMat: ShaderMaterial;
  const noiseTexture = imageLoader.load(noiseFile, (t) => { t.wrapS = t.wrapT = RepeatWrapping });
    scene.add(fireplace);
  function createFireplace() {
    // @ts-ignore fireplace
    fireplace = model.getObjectByName("fireplace");
    // @ts-ignore
    const fireplaceMap = fireplace.material.map;
    fireplaceMat = new ShaderMaterial({
      uniforms: {
        map: { value: fireplaceMap },
        ratio: { value: new Vector3(0.0, 1.0, 0.0) },
        gamma: { value: 1 }
      },
      vertexShader: basicVert,
      fragmentShader: rgbLightmapFrag
    });
    fireplace.material = fireplaceMat;

    // floor
    // @ts-ignore
    const floor:Mesh = model.getObjectByName("floor");
    // @ts-ignore
    const floorMap = floor.material.map;

    floorMat = fireplaceMat.clone();
    floorMat.uniforms.map.value = floorMap;
    // floorMat.uniforms.ratio.value= new Vector3(0.0, 1.0, 0.0);
    floor.material = floorMat;

    scene.add(fireplace);
    scene.add(floor);
  }

  function createFire() {
     fireMat = getFireMat(noiseTexture);

    const fireGeom = new CylinderGeometry(
      0.03,
      0.2,
      0.35,
      15,
      15,
      true,
      Math.PI *1,
      Math.PI
    );
    fire = new Mesh(fireGeom, fireMat);
    fire.position.set(0.1, 0, 0);
    fireplace.add(fire);
  }

  function createAshes() {
      ashesMat = getAshesMat(noiseTexture);  

    const ashesGeom = new CylinderGeometry(
      0.15,
      0.15,
      0.4,
      15,
      15,
      true,
      Math.PI / 2,
      Math.PI
    );
    // 只画了一半圆，所以旋转180度 但是我直接在绘制的时候就旋转了，下面的旋转就不需要了
    ashes = new Mesh(ashesGeom, ashesMat);
    ashes.position.set(0.1, 0, 0);// 这是为了调节和木头的相对位置。
    fireplace.add(ashes);
  }

  function  createPostProcessing() {
    const renderScene = new RenderPass(scene, camera);
    bloomPass = new UnrealBloomPass(
      new Vector2(1024, 1024),
      0.25,
      0.1,
      0.8
    );
// 没有outputpass也能用 这个通道似乎就只是调节色彩空间，是否太奢侈了，从一种可能性来说，渲染成一张纹理后，片元肯定减少了，是否是一种优化
    // const outputPass = new OutputPass();

    composer = new EffectComposer(renderer);
    composer.addPass(renderScene);
    composer.addPass(bloomPass);
  }
  function updateFire() {
    fireMat.uniforms.time.value = time * fireConfig.fireSpeed;
    ashesMat.uniforms.time.value = time * fireConfig.fireSpeed;
    
  }
  function updateLight() {
    const r =
      Math.abs(Math.sin(time) + Math.cos(time * 4 + 0.1) * 0.5) * 0.2;
    const g =
      Math.abs(
        Math.sin(time + Math.PI / 2) + Math.cos(time * 4 + 1.4) * 0.5
      ) * 0.2;
    const b = Math.abs(Math.sin(time + Math.PI)) * 0.2;
    let floorBrightness = 3,firePlaceBrightness = 1.5;  
    floorMat.uniforms.ratio.value.set( 0.1 + r *floorBrightness,0.1 + g * floorBrightness,0.1 + b * floorBrightness) 
    fireplaceMat.uniforms.ratio.value.set(0. + r * firePlaceBrightness,0 + g * firePlaceBrightness,0 + b * firePlaceBrightness);
    }

  function  render() {
    deltaTime = clock.getDelta();
    time += deltaTime;
    fireConfig.bloom ? composer.render() : renderer.render(scene, camera);
    // 压根儿就不需要辉光通道，用了辉光好像也没啥效果，有点儿效果，火光有时候可以闪一下
    updateFire();
    updateLight();
    if( fireConfig.needShot){
      canvasToImage(renderer.domElement,'firePlace');
      fireConfig.needShot = false;
    }
    requestAnimationFrame(render);
  }

  function initGUI() {
    const gui = new GUI();
    gui.add(fireConfig, "fireSpeed", 0.1, 10, 0.01);
    gui.add(bloomPass, "strength", 0, 1, 0.01);
    gui.add(fire ,'visible').name('fire');
    gui.add(ashes,'visible').name('ashes');
    gui.add(fireConfig,'bloom').name('辉光');
    gui.add(fireConfig,'shot').name('截图');
    // fireMat.uniforms.brightness.value = fireConfig.brightness;
    gui.add(fireConfig,'brightness',0,100,1).onChange((v) => {
      fireMat.uniforms.brightness.value = v;
    })
  }

  gltfLoader.load(gltfFile,(m) => {
    model = m.scene;
    const l1 = new DirectionalLight(0xffffff, .1);
    l1.position.set(1,1,1);
    scene.add(l1);
    createFireplace();
    createFire();
    createAshes();
    createPostProcessing();
    initGUI()
    render();
});
    /* const wall =  new Group();
    const wallMat = new MeshStandardMaterial({color:0xeeffff});
    const wallGeom1 = new BoxGeometry(10,1,40);
    const wallGeom2 = new BoxGeometry(10,10,1);
    wallGeom2.translate(0,0,-5);
    wallGeom1.translate(0,-2,0);
    const wallGeo = mergeGeometries([wallGeom1,wallGeom2]);
    const wallMesh = new Mesh(wallGeo,wallMat);
    wall.add(wallMesh); */
  
  return ;
}